package com.fognl.core.net.handler.request;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fognl.core.net.handler.AbstractRequest;
import com.fognl.core.net.handler.Request;
import com.fognl.core.net.handler.WorkerException;

/** Example of a Request that gets data from a database query and puts the results in a Map. */
public class SampleJdbcRequest extends AbstractRequest
{
	private String query;
	private Connection sqlConnection;
	
	public SampleJdbcRequest(Connection connection, String sql)
	{
		super();
		this.sqlConnection = connection;
		this.query = sql;
	}
	
	public String getQuery() { return query; }
	public Connection getSqlConnection() { return sqlConnection; }
	
	public String toString() { return "{JDBC Request: " + query + "}"; }

	public Worker getWorker()
	{
		return new Request.Worker() {
			List<Map<String, Object>> records = new ArrayList<Map<String, Object>>();
			
			public Object getData()
			{
				return records;
			}
			
			private List<String> getFieldNames(ResultSet rs) throws Exception
			{
				List<String> names = new ArrayList<String>();
				
				ResultSetMetaData meta = rs.getMetaData();
				int count = meta.getColumnCount();
				for(int i = 1; i <= count; ++i)
					names.add(meta.getColumnName(i));
				
				return names;
			}

			public void work(Request.Worker.Listener listener) throws WorkerException
			{
				try {
					Statement statement = sqlConnection.createStatement();
					
					try {
						ResultSet rs = statement.executeQuery(query);
						try {
							List<String> fieldNames = null;
							
							while(rs.next())
							{
								Thread.yield();
								if(!listener.okToContinue(this))
									break;
								
								if(fieldNames == null)
									fieldNames = getFieldNames(rs);
								
								Map<String, Object> record = new HashMap<String, Object>();
								
								for(String field: fieldNames)
									record.put(field, rs.getObject(field));

								// Send this record to the listener.
								listener.onData(record);
								
								records.add(record);
							}
						}
						finally {
							rs.close();
						}
					}
					finally {
						statement.close();
					}
				}
				catch(Exception ex)
				{
					throw new WorkerException(ex.getMessage(), ex);
				}
				finally {
					try {
						sqlConnection.close();
					} 
					catch(Exception ex) {}
				}
			}
		};
	}
}
